#include "kcentergreedycv.h"

KCenterGreedyCV& KCenterGreedyCV::instance() {
    static KCenterGreedyCV instance;
    return instance;
}

KCenterGreedyCV::KCenterGreedyCV(QObject* parent) : QObject(parent) {
    qInfo() << "KCenterGreedyCV initialized.";
}

void KCenterGreedyCV::buildKnowledgeBase() {
    qInfo() << "Building knowledge base from large dataset using k-means...";

    if (embedding.size() % D_ != 0) {
        qWarning() << "Invalid dataset dimensions. Aborting.";
        return;
    }

    totalPoints = embedding.size() / D_;
    if (totalPoints < N_) {
        qWarning() << "Total points less than N_, cannot perform k-means properly.";
        return;
    }

    // 将QVector<int8_t>转换为OpenCV的Mat，用于kmeans
    // 首先创建CV_8S类型的Mat，然后转为CV_32F，以便kmeans使用
    cv::Mat inputData(totalPoints, (int)D_, CV_8S, (void*)embedding.data());
    cv::Mat inputDataFloat;
    inputData.convertTo(inputDataFloat, CV_32F);

    // 使用OpenCV kmeans聚类
    int K = (int)N_;
    cv::Mat labels;
    cv::Mat centers;
    cv::TermCriteria criteria(cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 10000, 1e-6);

    // KMEANS_PP_CENTERS使用k-means++的初始化方式
    // attempts=1可以根据需求调整
    int attempts = 1;
    int flags = cv::KMEANS_PP_CENTERS;

    double compactness = cv::kmeans(inputDataFloat, K, labels, criteria, attempts, flags, centers);

    qInfo() << "K-means completed. Compactness:" << compactness;

    // centers是KxD的CV_32F矩阵，我们需要将其写回knowledgeBase_
    knowledgeBase_.resize(N_ * D_);
    for (int i = 0; i < (int)N_; i++) {
        for (int d = 0; d < (int)D_; d++) {
            float val = centers.at<float>(i, d);
            // 根据需求决定是否要转为int8_t，这里简单截断
            int16_t rounded = (int16_t)std::round(val);
            if (rounded > 127) rounded = 127;
            if (rounded < -128) rounded = -128;
            knowledgeBase_[i * D_ + d] = static_cast<int8_t>(rounded);
        }
    }

    qInfo() << "Knowledge base built with size:" << N_;
}

void KCenterGreedyCV::addToKnowledgeBase(const QVector<int8_t>& newData) {
    qInfo() << "Adding new data to knowledge base...";
    if (newData.size() != (size_t)onceN_ * D_) {
        qWarning() << "Invalid new data dimensions. Aborting.";
        return;
    }

    // 将新数据拼接到embedding中，然后重新聚类
    size_t oldSize = embedding.size();
    embedding.resize(oldSize + (size_t)onceN_ * D_);
    memcpy(embedding.data() + oldSize, newData.data(), (size_t)onceN_ * D_);

    // 重新构建知识库（聚类）
    buildKnowledgeBase();
    qInfo() << "Knowledge base updated with new data.";
}


